# Responsability
# Execute four models paralelized in different slaves

MpiMaster <- setRefClass(    
  "mpimaster"
  
  , fields = list(
      feeder="slavesfeeder"
    )
  , methods = list(
    #
    #
    # Constructor
    #
    #
    initialize = function(..., feeder=NULL)
    {
      callSuper(..., feeder=feeder)
    },
    #
    #
    # Prepare the mpi execution of varios tasks
    #
    #
    executeParallelTasks = function(tasks) {
      
      # Notice we just say "give us all the slaves you've got."
      mpi.spawn.Rslaves(needlog = TRUE, quiet = FALSE)
      
      if (mpi.comm.size() < 2) {
        mpi.quit()
        stop("More slave processes are required.")
      }
      
      .Last <- function() {
        if (is.loaded("mpi_initialize")) {
          if (mpi.comm.size(1) > 0){
            print("Please use mpi.close.Rslaves() to close slaves.")
            mpi.close.Rslaves()
          }
          print("Please use mpi.quit() to quit R")
          .Call("mpi_finalize")
        }
      }
      
      # Prepare slaves for working
      feeder$feedSlaves()
      feeder$whipSlaves()
        
      # Create data structure to store the results
      chainResults = list()
      
      junk <- 0 
      closed_slaves <- 0 
      n_slaves <- mpi.comm.size()-1 
      
      while (closed_slaves < n_slaves) { 
        # Receive a message from a slave 
        message <- mpi.recv.Robj(mpi.any.source(),mpi.any.tag()) 
        message_info <- mpi.get.sourcetag() 
        slave_id <- message_info[1] 
        tag <- message_info[2] 
        
        taskNumber <- 1
        
        if (tag == 1) {
          print("Tag1: Slave ready")
          # slave is ready for a task. Give it the next task, or tell it tasks 
          # are done if there are none. 
          if (length(tasks) > 0) { 
            # Send a task, and then remove it from the task list
            #Aqui habra que ver si mandamos ejecuciones ldndc o calculos estadisticos de metropolis.
                        
            lastParameters <- tasks[[taskNumber]]$chainState$lastParameters
            #TODO: create just one in initialize and use a global field (UPDATE: it give me an error ?)
            parametersGenerator <- ParametersGenerator(parameterDistribution=priorProbabilityDistribution)
            tasks[[taskNumber]]$chainState$candidateParameters <- parametersGenerator$newRandomParameters(lastParameters)
            
            mpi.send.Robj(tasks[[taskNumber]], slave_id, 1); 
            
            tasks[[taskNumber]] <- NULL 
            taskNumber <- taskNumber + 1
            
          } else { 
            print("No more tasks")
            mpi.send.Robj(junk, slave_id, 2) 
          } 
        } 
        else if (tag == 2) {
          print("tag2")

          chainResults[[length(chainResults)+1]]<- list(chainState=message$chainState)
        } 
        else if (tag == 3) {
          print("tag3")
          # A slave has closed down. 
          closed_slaves <- closed_slaves + 1 
        } 
      }
      
      mpi.close.Rslaves()
      
      
      #Close mpi environment and detach Rmpi
      #mpi.exit()
      #Quit close all R environment
      #mpi.quit(save="no")
      
      chainResults
    }
    
  )
)




